package com.core.indexer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class IndexData {

	private static IndexData mInstance = null;
	private boolean mSearchMode = false;
	
	public static IndexData Get()
	{
		if(mInstance == null)
			mInstance = new IndexData();
		
		return mInstance;
	}
	
	private IndexData(){}
	
	//public static int sequentialId;	// Need to keep a static sequential counter to ensure unique ids for mapping 
	
	private Map<String, Lexicon> mMapLexicon;
	private ArrayList<InvList> mArrListInvList;

	public void Init(boolean bIsSearch)
	{
		mSearchMode = bIsSearch;
		mMapLexicon = new HashMap<String, Lexicon>();
		mArrListInvList = new ArrayList<InvList>();
	}
	
	public Lexicon GetNewLexicon(String keyWord, int count, int position)
	{
		return new Lexicon(keyWord, count, position);
	}

	public Lexicon GetNewLexicon(String keyWord, int count, int position, int offset)
	{
		return new Lexicon(keyWord, count, position, offset);
	}
	
	public Map<String, Lexicon> getAllLexicon() {
		return mMapLexicon;
	}
	
	public ArrayList<InvList> getInvList() {
		return mArrListInvList;
	}
	
	
	public void FillInData(Map<String, Lexicon> mapLexicon, int nDocPos)
	{

		if(mSearchMode)
			return;
		
		for(Lexicon lexicon : mapLexicon.values())
		{
			InvList tmpInvList = null;
			Lexicon tmpLexicon = null;
			
			if(!mMapLexicon.containsKey(lexicon.GetKeyWord()))
			{
				tmpInvList = new InvList(lexicon.GetKeyWord());
				int nPos = mArrListInvList.size(); //Get the position before size() call, pos starts from 0
				mArrListInvList.add(tmpInvList);	
				tmpLexicon = new Lexicon(lexicon.GetKeyWord(), 1, nPos);
				mMapLexicon.put(tmpLexicon.GetKeyWord(), tmpLexicon);
				
			}
			else
			{
				tmpLexicon = mMapLexicon.get(lexicon.GetKeyWord());
				tmpLexicon.IncRef();
				tmpInvList = mArrListInvList.get(tmpLexicon.GetPosition());
			}
			tmpInvList.mDocIDToLexiconCount.put(nDocPos, lexicon.GetCount());
		}
	}

	public Lexicon GetLexiconByKeyword(String keyWord)
	{
		return mMapLexicon.get(keyWord);
	}
	
	public void AddLexicon(String keyWord, int count, int pos, int offset)
	{
		if(!mSearchMode)
			return;
		Lexicon lexicon= new Lexicon(keyWord, count, pos, offset);
		mMapLexicon.put(keyWord, lexicon);
	}
	
	// Calculate the file offset for each Inverted List
	public void ComputeInvertedListOffset() {
		int nextOffset = 0;
//		for (String key : mMapLexicon.keySet()) {
//			mMapLexicon.get(key).mInvertedListOffset = nextOffset;
//			nextOffset = nextOffset + mMapLexicon.get(key).mCount;
//		}
		for(InvList list : mArrListInvList)
		{
			Lexicon lexicon = mMapLexicon.get(list.mKeyWord);
			if(lexicon == null)
			{
				System.out.println(String.format("ComputeInvertedListOffset() KeyWord[%s] not in Lexicon Map! Offset Not usable!", list.mKeyWord));
				return;
			}
			lexicon.mInvertedListOffset = nextOffset;
			nextOffset += lexicon.mCount;
		}
	}
	
	public class Lexicon{
		
		private String mKeyWord;
		private int mCount;
		private int mPosition;
		private int mInvertedListOffset;
		
		
		public Lexicon(String keyWord, int count, int position) {
			this.mKeyWord = keyWord;
			this.mCount = count;
			this.mPosition = position;
		}
		
		public Lexicon(String keyWord, int count, int position, int offset) {
			this.mKeyWord = keyWord;
			this.mCount = count;
			this.mPosition = position;
			this.mInvertedListOffset = offset;
		}
		
		public String GetKeyWord() { return mKeyWord; }
		public int GetPosition() { return mPosition; }
		public int GetCount() { return mCount; }
		public void IncRef() { mCount++; }
		public int getInvertedListOffset() {return mInvertedListOffset;}
	}

	public class InvList{
		
		public Map<Integer, Integer> mDocIDToLexiconCount;
		public String mKeyWord;
		public InvList(String keyWord)
		{
			mDocIDToLexiconCount = new HashMap<Integer, Integer>();
			mKeyWord = keyWord;
		}
	}
	
	public class DocList{
		public String DocNo;
		public double DocWeight;
		public int DocSize;
		public double DocScore;
		
		public DocList(String docNo, double score)
		{
			this.DocNo = docNo;
			this.DocScore = score;
		}
		
		public DocList(String docNo, double docWeight, int docSize)
		{
			DocNo = docNo;
			DocWeight = docWeight;
			DocSize = docSize;
			DocScore = 0;
		}
	}
}
